/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hos_ahmedadeltito.photoeditorsdk;

import ohos.agp.components.*;
import ohos.agp.utils.Rect;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.util.logging.Logger;

public class MultiTouchListener implements Component.TouchEventListener {

    private boolean isRotateEnabled = true;
    private boolean isTranslateEnabled = true;
    private boolean isScaleEnabled = true;
    private float minimumScale = 0.5f;
    private float maximumScale = 10.0f;


    private int[] location = new int[2];
    private Rect outRect;
    private Component deleteView;
    private Image photoEditImageView;
    private DependentLayout parentView;
    private OnMultiTouchListener onMultiTouchListener;
    private OnPhotoEditorSDKListener onPhotoEditorSDKListener;
    private float scaleX = 1f;
    private float scaleY = 1f;
    // 按下时候手指坐标点
    private MmiPoint[] mPointerStart = new MmiPoint[2];
    // 位移手指的坐标点
    private MmiPoint[] mPointerEnd = new MmiPoint[2];
    // 单指按下时控件的位移距离
    private Float[] componentTranslation = new Float[2];

    MultiTouchListener(Component deleteView, DependentLayout parentView,
                       Image photoEditImageView, OnPhotoEditorSDKListener onPhotoEditorSDKListener) {

        this.deleteView = deleteView;
        this.parentView = parentView;
        this.photoEditImageView = photoEditImageView;
        this.onPhotoEditorSDKListener = onPhotoEditorSDKListener;
        outRect = new Rect(deleteView.getLeft(), deleteView.getTop(),
            deleteView.getRight(), deleteView.getBottom());
    }

    private static float adjustAngle(float degrees) {
        if (degrees > 180.0f) {
            degrees -= 360.0f;
        } else if (degrees < -180.0f) {
            degrees += 360.0f;
        }
        return degrees;
    }


    private static void computeRenderOffset(Component view, float pivotX, float pivotY) {
        if (view.getPivotX() == pivotX && view.getPivotY() == pivotY) {
            return;
        }
        float[] prevPoint = {0.0f, 0.0f};
        //todo 未找到解决方案
//        view.getMatrix().mapPoints(prevPoint);
        view.setPivotX(pivotX);
        view.setPivotY(pivotY);
        float[] currPoint = {0.0f, 0.0f};
        //todo 未找到解决方案
//        view.getMatrix().mapPoints(currPoint);
        float offsetX = currPoint[0] - prevPoint[0];
        float offsetY = currPoint[1] - prevPoint[1];
        view.setTranslationX(view.getTranslationX() - offsetX);
        view.setTranslationY(view.getTranslationY() - offsetY);
    }


    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!isTranslateEnabled) {
            return true;
        }
        int action = touchEvent.getAction();

        switch (action & touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                mPointerStart[0] = touchEvent.getPointerScreenPosition(0);
                componentTranslation[0] = component.getTranslationX();
                componentTranslation[1] = component.getTranslationY();
                deleteView.setVisibility(Component.VISIBLE);
                //todo 未找到解决方案 改变view的z轴，使其处在他父view的顶端
//                view.bringToFront();

                firePhotoEditorSDKListener(component, true);
                break;
            case TouchEvent.OTHER_POINT_DOWN:
                mPointerStart[0] = touchEvent.getPointerScreenPosition(0);
                mPointerStart[1] = touchEvent.getPointerScreenPosition(1);
                break;
            case TouchEvent.POINT_MOVE:
                if (touchEvent.getPointerCount() == 1) {
                    Logger.getGlobal().warning("手指 = 1");
                    mPointerEnd[0] = touchEvent.getPointerScreenPosition(0);
                    Float[] mPointOneMove = getPointMoveXY(mPointerStart[0].getX(), mPointerStart[0].getY()
                        , mPointerEnd[0].getX(), mPointerEnd[0].getY());
                    setPointScalingDisplacement(component, mPointOneMove);
                } else if (touchEvent.getPointerCount() > 1) {
                    Logger.getGlobal().warning("手指 = 2");
                    mPointerEnd[0] = touchEvent.getPointerScreenPosition(0);
                    mPointerEnd[1] = touchEvent.getPointerScreenPosition(1);
                    setPointScalingDisplacement(component, mPointerStart, mPointerEnd);
                }
                break;

            case TouchEvent.PRIMARY_POINT_UP:
                componentTranslation[0] = component.getTranslationX();
                componentTranslation[1] = component.getTranslationY();
                if (isViewInBounds(deleteView, mPointerEnd[0])) {
                    if (onMultiTouchListener != null)
                        onMultiTouchListener.onRemoveViewListener(component);
                } else if (!isViewInBounds(photoEditImageView, mPointerEnd[0])) {
                    component.setTranslation(0, 0);

                }
                deleteView.setVisibility(component.HIDE);
                firePhotoEditorSDKListener(component, false);
                float mCurrentCancelX = touchEvent.getPointerScreenPosition(0).getX();
                float mCurrentCancelY = touchEvent.getPointerScreenPosition(0).getY();
                if (mCurrentCancelX == mPointerStart[0].getX() || mCurrentCancelY == mPointerStart[0].getY()) {
                    if (component instanceof Text) {
                        if (onMultiTouchListener != null) {
                            onMultiTouchListener.onEditTextClickListener(
                                ((Text) component).getText(), ((Text) component).getTextColor().getValue());
                        }
                        if (onPhotoEditorSDKListener != null) {
                            onPhotoEditorSDKListener.onEditTextChangeListener(
                                ((Text) component).getText(), ((Text) component).getTextColor().getValue());
                        }
                    }
                }
                break;
            case TouchEvent.OTHER_POINT_UP:
                int pointerIndexPointerUp = (action & touchEvent.getIndex()) >> touchEvent.getIndex();
                int pointerId = touchEvent.getPointerId(pointerIndexPointerUp);
                break;
        }
        return true;
    }


    private void firePhotoEditorSDKListener(Component view, boolean isStart) {
        if (view instanceof Text) {
            if (onMultiTouchListener != null) {
                if (onPhotoEditorSDKListener != null) {
                    if (isStart)
                        onPhotoEditorSDKListener.onStartViewChangeListener(ViewType.TEXT);
                    else
                        onPhotoEditorSDKListener.onStopViewChangeListener(ViewType.TEXT);
                }
            } else {
                if (onPhotoEditorSDKListener != null) {
                    if (isStart)
                        onPhotoEditorSDKListener.onStartViewChangeListener(ViewType.EMOJI);
                    else
                        onPhotoEditorSDKListener.onStopViewChangeListener(ViewType.EMOJI);
                }
            }
        } else {
            if (onPhotoEditorSDKListener != null) {
                if (isStart)
                    onPhotoEditorSDKListener.onStartViewChangeListener(ViewType.IMAGE);
                else
                    onPhotoEditorSDKListener.onStopViewChangeListener(ViewType.IMAGE);
            }
        }
    }

    private boolean isViewInBounds(Component view, MmiPoint mPoint) {
        boolean isViewInBounds = false;
        if (mPoint != null) {
            if (mPoint.getX() >= view.getLocationOnScreen()[0] && mPoint.getX() <= (view.getLocationOnScreen()[0] + view.getWidth())) {
                if (mPoint.getY() >= view.getLocationOnScreen()[1] && mPoint.getY() <= (view.getLocationOnScreen()[1] + view.getHeight())) {
                    isViewInBounds = true;
                }
            }
        }
        return isViewInBounds;
    }

    public void setOnMultiTouchListener(OnMultiTouchListener onMultiTouchListener) {
        this.onMultiTouchListener = onMultiTouchListener;
    }

    public Float[] getPointMoveXY(float startX, float startY, float endX, float endY) {
        Float[] moveXY = new Float[2];
        /**
         * 计算控件XY位移的值;
         * moveXY[0] 为X轴,负数向左移动,正数右移动
         * moveXY[1] 为Y轴,负数向下移动,正数上移动
         */
        moveXY[0] = endX - startX;
        moveXY[1] = endY - startY;
        return moveXY;
    }

    /**
     * 单指位移
     *
     * @param component
     * @param pointOne 手指1位移的XY轴变量 getPointMoveXY(float startX, float startY, float endX, float endY)
     */
    public void setPointScalingDisplacement(Component component, Float[] pointOne) {
        if (component == null || pointOne == null) {
            throw new NullPointerException("not find component or pointOne!!!");
        }
        component.setTranslationX(componentTranslation[0] + pointOne[0]);
        component.setTranslationY(componentTranslation[1] + pointOne[1]);
    }

    /**
     * 双指 位移 缩放
     *
     * @param component
     * @param mPointerStart 初始化双指坐标点
     * @param mPointerEnd 位移后双指坐标点
     */
    public void setPointScalingDisplacement(Component component, MmiPoint[] mPointerStart, MmiPoint[] mPointerEnd) {
        if (component == null || mPointerStart == null || mPointerEnd == null) {
            throw new NullPointerException("not find component or pointOne!!!");
        }

        // 双指中心点 pointCenter[0]为mPointerStart中心点,pointCenter[1]为mPointerEnd中心点
        Float[][] pointCenter = {new Float[2], new Float[2]};
        pointCenter[0] = getTwoPointCenter(mPointerStart[0], mPointerStart[1]);

        pointCenter[1] = getTwoPointCenter(mPointerEnd[0], mPointerEnd[1]);
        // 位移双指中心点
        setComponentTranslation(component, mPointerStart[0], mPointerStart[1], mPointerEnd[0], mPointerEnd[1]);

        // 缩放，初始化双指距离,和停止后双指的距离比
        setComponentZoom(component, mPointerStart[0], mPointerStart[1], mPointerEnd[0], mPointerEnd[1]);
        // 旋转
        setComponentRotation(component, mPointerStart[0], mPointerStart[1], mPointerEnd[0], mPointerEnd[1]);

    }

    //获取中心点
    public Float[] getTwoPointCenter(MmiPoint pointOne, MmiPoint pointTwo) {
        Float[] centerPoint = new Float[2];
        centerPoint[0] = (pointOne.getX() + pointTwo.getX()) / 2;
        centerPoint[1] = (pointOne.getY() + pointTwo.getY()) / 2;
        return centerPoint;
    }

    /**
     * 双指位移Veiw
     *
     * @param component 需要移动的控件
     * @param startPointOne 第二根手指按下时,第一根手指的坐标
     * @param startPointTwo 第二根手指按下时候的坐标
     * @param endPointOne 位移后第一根手指坐标
     * @param endPointTwo 位移后第二根手指的坐标
     */
    public void setComponentTranslation(Component component, MmiPoint startPointOne, MmiPoint startPointTwo, MmiPoint endPointOne, MmiPoint endPointTwo) {
        Float[][] centerPoint = new Float[2][2];
        centerPoint[0] = getTwoPointCenter(startPointOne, startPointTwo);
        centerPoint[1] = getTwoPointCenter(endPointOne, endPointTwo);
        component.setTranslationX(componentTranslation[0] + (centerPoint[1][0] - centerPoint[0][0]));
        component.setTranslationY(componentTranslation[1] + (centerPoint[1][1] - centerPoint[0][1]));
    }

    /**
     * 缩放Veiw
     *
     * @param component 需要移动的控件
     * @param startPointOne 第二根手指按下时,第一根手指的坐标
     * @param startPointTwo 第二根手指按下时候的坐标
     * @param endPointOne 位移后第一根手指坐标
     * @param endPointTwo 位移后第二根手指的坐标
     */
    public void setComponentZoom(Component component, MmiPoint startPointOne, MmiPoint startPointTwo, MmiPoint endPointOne, MmiPoint endPointTwo) {
        //TODO 每次都会初始化为原来大小.
        //计算X轴缩放
        float startX = Math.abs(startPointTwo.getX() - startPointOne.getX());
        float endX = Math.abs(endPointTwo.getX() - endPointOne.getX());
        float scaleFactorX = (1 + ((endX - startX) / component.getWidth()));
        //计算Y轴缩放
        float startY = Math.abs(startPointTwo.getY() - startPointOne.getY());
        float endY = Math.abs(endPointTwo.getY() - endPointOne.getY());
        float scaleFactorY = 1 + ((endY - startY) / component.getHeight());

        scaleX = (scaleFactorX) > maximumScale ? maximumScale : ((scaleFactorX) < minimumScale ? minimumScale : (scaleFactorX));
        component.setScaleX(scaleX);

        scaleY = (scaleFactorY) > maximumScale ? maximumScale : ((+scaleFactorY) < minimumScale ? minimumScale : (scaleFactorY));
        component.setScaleY(scaleY);
    }


    /**
     * 旋转Veiw
     *
     * @param component 需要移动的控件
     * @param startPointOne 第二根手指按下时,第一根手指的坐标
     * @param startPointTwo 第二根手指按下时候的坐标
     * @param endPointOne 位移后第一根手指坐标
     * @param endPointTwo 位移后第二根手指的坐标
     */
    private void setComponentRotation(Component component, MmiPoint startPointOne, MmiPoint startPointTwo, MmiPoint endPointOne, MmiPoint endPointTwo) {
        double startRotation = Math.atan2(startPointOne.getY() - startPointTwo.getY(), startPointOne.getX() - startPointTwo.getX()) * (180 / Math.PI);
        double endRotation = Math.atan2(endPointOne.getY() - endPointTwo.getY(), endPointOne.getX() - endPointTwo.getX()) * (180 / Math.PI);
        double relativeRotation = endRotation - startRotation;
        component.setRotation((float) relativeRotation);
    }

    private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        private float mPivotX;
        private float mPivotY;
        private Vector2D mPrevSpanVector = new Vector2D();

        @Override
        public boolean onScaleBegin(Component view, ScaleGestureDetector detector) {
            mPivotX = detector.getFocusX();
            mPivotY = detector.getFocusY();
            mPrevSpanVector.modify(detector.getCurrentSpanVector());
            return true;
        }

        @Override
        public boolean onScale(Component view, ScaleGestureDetector detector) {
            TransformInfo info = new TransformInfo();
            info.deltaScale = isScaleEnabled ? detector.getScaleFactor() : 1.0f;
            info.deltaAngle = isRotateEnabled ? Vector2D.getAngle(mPrevSpanVector, detector.getCurrentSpanVector()) : 0.0f;
            info.deltaX = isTranslateEnabled ? detector.getFocusX() - mPivotX : 0.0f;
            info.deltaY = isTranslateEnabled ? detector.getFocusY() - mPivotY : 0.0f;
            info.pivotX = mPivotX;
            info.pivotY = mPivotY;
            info.minimumScale = minimumScale;
            info.maximumScale = maximumScale;

            return false;
        }
    }

    private class TransformInfo {
        float deltaX;
        float deltaY;
        float deltaScale;
        float deltaAngle;
        float pivotX;
        float pivotY;
        float minimumScale;
        float maximumScale;
    }

    interface OnMultiTouchListener {
        void onEditTextClickListener(String text, int colorCode);
        void onRemoveViewListener(Component removedView);
    }
}
